﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Threading;
using SLS.ExClassLib.RTIService;
using SLS.ExClassLib.RTIService;
using SLS.ExClassLib.Event;
using SLS.ExClassLib.Events;
using SLS.ExClassLib.ExThreading;
using SLS.ExClassLib.Message;
namespace SLS.Core.HLASimu
{
    public class Federate : DispatcherObject
    {
        public delegate void ExThreadDelegate(MessageEx msg);
        public string FEDName;
        public SortedDictionary<long, ArrayList> MessagePool;
        public WorkQueue JobQueue;
        public string ClientType;
        public object XRTIServiceClient;
        public ExThreadDelegate m_SendMessage;
        public ExThreadDelegate m_ReceiveMessage;
        private long LastTimeStamp = DateTime.Now.Ticks;
        private ArrayList TimeTableList;
        public Federate()
        { 
            CreateNewJobQueue();
        }
        public Federate(string m_ClientType, string m_FEDName, object m_RTIServiceClient)
        { 
            CreateNewJobQueue();
            this.ClientType = m_ClientType;
            this.FEDName = m_FEDName;
            this.XRTIServiceClient = m_RTIServiceClient;
            if (m_RTIServiceClient.GetType() != typeof(RTIServiceClient))
            {
                return;
            }
            if (ContactRTIService.Instance.MasterRTIServiceClient == null)
            {
                ContactRTIService.Instance.MasterRTIServiceClient = (RTIServiceClient)m_RTIServiceClient;
            }
        }
        public void CreateNewJobQueue()
        {
            m_SendMessage = new ExThreadDelegate(SendMessage);
            m_ReceiveMessage = new ExThreadDelegate(ReceiveMessage);
            JobQueue = new WorkQueue();
            JobQueue.ConcurrentLimit = 20;
            ((WorkThreadPool)JobQueue.WorkerPool).MaxThreads = 10;
            JobQueue.AllWorkCompleted += new EventHandler(work_AllWorkCompleted);
            JobQueue.WorkerException += new ResourceExceptionEventHandler(work_WorkerException);
            JobQueue.ChangedWorkItemState += new ChangedWorkItemStateEventHandler(work_ChangedWorkItemState);
            MessagePool = new SortedDictionary<long, ArrayList>();
            TimeTableList = new ArrayList();
            TimeTableList.Sort();
        }
        public virtual void work_ChangedWorkItemState(object sender, ChangedWorkItemStateEventArgs e)
        {
          
        }
        public virtual void MakeUpMessage(string CallerType,ref MessageEx msg, object Data=null,string Action="")
        {
            try
            {
                EventDispatcher.Instance.MessagePool.Add(msg);
            }
            catch(Exception ex)
            {
                throw;
            } 
        }
        public virtual MessageEx EndUpMessage(MessageEx msgA, MessageEx msgB)
        { 
            try
            {
                //msgB回复了msgA
                msgB=EventDispatcher.Instance.MessagePool.Answer(msgA, msgB);
            }
            catch (Exception ex)
            {
                throw;
            }
            return msgB;
        }
        private void work_AllWorkCompleted(object sender, EventArgs e)
        {

            if (this.Dispatcher.CheckAccess())
            {
                Application.Current.Dispatcher.BeginInvoke(new EventHandler(work_AllWorkCompleted), DispatcherPriority.Background, new object[] { sender, e });
            }
        }
        private void work_WorkerException(object sender, ResourceExceptionEventArgs ex)
        {
            Tracer.Error(ex.Exception.StackTrace, ex.Exception);
        }
        public virtual void SendMessage(MessageEx msg)
        {
            
        }
        public virtual void ReceiveMessage(MessageEx msg)
        {
            try
            {
                ArrayList msgList = null;
                long timestamp = msg.TimeStamp.Ticks;
                if (MessagePool.ContainsKey(timestamp))
                {
                    msgList = MessagePool[timestamp];
                    msgList.Add(msg);
                    if(!TimeTableList.Contains(timestamp))
                    {
                        TimeTableList.Add(timestamp);
                    }
                    Tracer.Info(this.FEDName, "Receive message"+ msg.MessageID.ToString()+"  at " + timestamp.ToString());
                }
                else
                {
                    msgList = new ArrayList();
                    msgList.Add(msg);
                    MessagePool.Add(timestamp, msgList);
                    if (!TimeTableList.Contains(timestamp))
                    {
                        TimeTableList.Add(timestamp);
                    }
                    Tracer.Info(this.FEDName, "Receive message" + msg.MessageID.ToString() + "  at " + timestamp.ToString());
                }
            }
            catch (Exception ex)
            {
                throw;
            }
        }
        public virtual ArrayList GetMessage(bool FIFO=true)
        {
            ArrayList msgList = new ArrayList();
            MessageEx msgp,msg = null;
            try
            {
                if (MessagePool.Count == 0)
                    return msgList;
                long timestamp;
                TimeTableList.Sort();
                timestamp = (long)TimeTableList[0];
                msgList = MessagePool[timestamp];
                msg = (MessageEx)msgList[0];
                if (FIFO)
                {
                    Tracer.Info(this.FEDName, "Has message MessagePool.Count." + MessagePool.Count.ToString() + " at " + timestamp.ToString());
                    LastTimeStamp = timestamp;
                    MessagePool.Remove(timestamp);
                    TimeTableList.Remove(timestamp);
                    Tracer.Info(this.FEDName, "Remove message at MessagePool.Count." + MessagePool.Count.ToString() +" at "+ timestamp.ToString());
                    return msgList;
                }                
                object tag = msg.Tag;
                msg.Tag = msgList.Count;
                int msgnum = (int)((RTIServiceClient)XRTIServiceClient).GetMessgeOnWallTimeTable(msg).Tag;
                if (msgnum == 1)
                {
                    LastTimeStamp = msg.TimeStamp.Ticks;
                    MessagePool.Remove(LastTimeStamp);
                    TimeTableList.Remove(LastTimeStamp);
                }
                else
                {
                    msgList = new ArrayList();
                }
                msg.Tag = tag;
            }
            catch (Exception ex)
            {
                throw;
            }
            return msgList;
        }
        public virtual void BuildWorkQueue(MessageEx msg)
        {
            ExWorkItem workItem = new ExWorkItem(msg, null);
            JobQueue.Add(workItem);
        }
    }
}
